package inc.gome.dynamic.datasource.lock;

import inc.gome.dynamic.datasource.lock.constant.BranchType;
import inc.gome.dynamic.datasource.lock.constant.GlobalStatus;
import inc.gome.dynamic.datasource.lock.constant.RootContext;
import inc.gome.dynamic.datasource.lock.exception.BranchTransactionException;
import inc.gome.dynamic.datasource.lock.exception.GlobalTransactionException;
import inc.gome.dynamic.datasource.lock.exception.TransactionException;
import inc.gome.dynamic.datasource.lock.exception.TransactionExceptionCode;
import inc.gome.dynamic.datasource.lock.session.BranchSession;
import inc.gome.dynamic.datasource.lock.session.GlobalSession;
import inc.gome.dynamic.datasource.lock.session.SessionHelper;
import inc.gome.dynamic.datasource.lock.session.SessionHolder;
import org.slf4j.MDC;

/**
 * @author sujizhou
 * @Date 2021/12/22
 * @Desc 类描述信息
 */
public class LockDemo {

    public static void main(String[] args)  throws TransactionException{
        try {
            //初始化
            SessionHolder.init("file");
            //SessionManager sessionManager = new FileSessionManager("root.data", ".");

            GlobalSession globalSession1 = new GlobalSession
                    ("demo-app", "my_test_tx_group", "test", 6000);
            System.out.println("全局事务标识："+globalSession1.getXid());
            SessionHolder.getRootSessionManager().addGlobalSession(globalSession1);

            /**/

            //全局session
            GlobalSession globalSession = assertGlobalSessionNotNull(globalSession1.getXid(), false);
            Long mysql_connect = SessionHolder.lockAndExecute(globalSession, () -> {
                globalSessionStatusCheck(globalSession);
                globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
                BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, "mysql_connect",
                        null, "tbl:151", "127.0.0.1");
                //X-TX-BRANCH-ID
                MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId()));

                //ATCore
                branchSessionLock(globalSession, branchSession);  //分支锁 锁细粒度
                try {
                    globalSession.addBranch(branchSession);
                } catch (RuntimeException ex) {
                    branchSessionUnlock(branchSession);
                    throw new BranchTransactionException(TransactionExceptionCode.FailedToAddBranch, String
                            .format("Failed to store branch xid = %s branchId = %s", globalSession.getXid(),
                                    branchSession.getBranchId()), ex);
                }
                return branchSession.getBranchId();
            });

            System.out.println(mysql_connect);


        }catch (Exception e){
            e.printStackTrace();
        }


    }



    protected static void branchSessionUnlock(BranchSession branchSession) throws TransactionException {
        branchSession.unlock();
    }


    // 分支 session  lock
    protected static void branchSessionLock(GlobalSession globalSession, BranchSession branchSession) throws TransactionException {
        if (!branchSession.lock()) {
            //锁冲突
            throw new BranchTransactionException(TransactionExceptionCode.LockKeyConflict, String
                    .format("Global lock acquire failed xid = %s branchId = %s", globalSession.getXid(),
                            branchSession.getBranchId()));
        }
    }



   //GlobalSession Status Check
    protected static void globalSessionStatusCheck(GlobalSession globalSession) throws GlobalTransactionException {
        if (!globalSession.isActive()) {
            throw new GlobalTransactionException(TransactionExceptionCode.GlobalTransactionNotActive, String.format(
                    "Could not register branch into global session xid = %s status = %s, cause by globalSession not active",
                    globalSession.getXid(), globalSession.getStatus()));
        }
        if (globalSession.getStatus() != GlobalStatus.Begin) {
            throw new GlobalTransactionException(TransactionExceptionCode.GlobalTransactionStatusInvalid, String
                    .format("Could not register branch into global session xid = %s status = %s while expecting %s",
                            globalSession.getXid(), globalSession.getStatus(), GlobalStatus.Begin));
        }
    }


    private static GlobalSession assertGlobalSessionNotNull(String xid, boolean withBranchSessions)
            throws TransactionException {
        GlobalSession globalSession = SessionHolder.findGlobalSession(xid, withBranchSessions);  //校验Global全局锁
        if (globalSession == null) {
            throw new GlobalTransactionException(TransactionExceptionCode.GlobalTransactionNotExist,
                    String.format("Could not found global transaction xid = %s, may be has finished.", xid));
        }
        return globalSession;
    }
}
